home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume24 / gnudiff1.15 / part03 < prev    next >
Encoding:
Internet Message Format  |  1991-03-05  |  52.4 KB

  1. Subject:  v24i018:  GNU Diff, version 1.15, Part03/08
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: e98e62c7 1a384528 e8ba3cb5 deb69a40
  5.  
  6. Submitted-by: Paul Eggert <eggert@twinsun.com>
  7. Posting-number: Volume 24, Issue 18
  8. Archive-name: gnudiff1.15/part03
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 3 (of 8)."
  17. # Contents:  diff.c getopt.c util.c
  18. # Wrapped by eggert@ata on Mon Jan  7 11:25:29 1991
  19. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  20. if test -f 'diff.c' -a "${1}" != "-c" ; then 
  21.   echo shar: Will not clobber existing file \"'diff.c'\"
  22. else
  23. echo shar: Extracting \"'diff.c'\" \(17901 characters\)
  24. sed "s/^X//" >'diff.c' <<'END_OF_FILE'
  25. X/* GNU DIFF main routine.
  26. X   Copyright (C) 1988, 1989 Free Software Foundation, Inc.
  27. X
  28. XThis file is part of GNU DIFF.
  29. X
  30. XGNU DIFF is free software; you can redistribute it and/or modify
  31. Xit under the terms of the GNU General Public License as published by
  32. Xthe Free Software Foundation; either version 1, or (at your option)
  33. Xany later version.
  34. X
  35. XGNU DIFF is distributed in the hope that it will be useful,
  36. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  37. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  38. XGNU General Public License for more details.
  39. X
  40. XYou should have received a copy of the GNU General Public License
  41. Xalong with GNU DIFF; see the file COPYING.  If not, write to
  42. Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  43. X
  44. X/* GNU DIFF was written by Mike Haertel, David Hayes,
  45. X   Richard Stallman and Len Tower.  */
  46. X
  47. X#define GDIFF_MAIN
  48. X#include "regex.h"
  49. X#include "diff.h"
  50. X#include "getopt.h"
  51. X
  52. X
  53. X/* Nonzero for -r: if comparing two directories,
  54. X   compare their common subdirectories recursively.  */
  55. X
  56. Xint recursive;
  57. X
  58. X/* For debugging: don't do discard_confusing_lines.  */
  59. X
  60. Xint no_discards;
  61. X
  62. X/* Return a string containing the command options with which diff was invoked.
  63. X   Spaces appear between what were separate ARGV-elements.
  64. X   There is a space at the beginning but none at the end.
  65. X   If there were no options, the result is an empty string.
  66. X
  67. X   Arguments: OPTIONVEC, a vector containing separate ARGV-elements, and COUNT,
  68. X   the length of that vector.  */
  69. X
  70. Xstatic char *
  71. Xoption_list (optionvec, count)
  72. X     char **optionvec;  /* Was `vector', but that collides on Alliant.  */
  73. X     int count;
  74. X{
  75. X  int i;
  76. X  int length = 0;
  77. X  char *result;
  78. X
  79. X  for (i = 0; i < count; i++)
  80. X    length += strlen (optionvec[i]) + 1;
  81. X
  82. X  result = (char *) xmalloc (length + 1);
  83. X  result[0] = 0;
  84. X
  85. X  for (i = 0; i < count; i++)
  86. X    {
  87. X      strcat (result, " ");
  88. X      strcat (result, optionvec[i]);
  89. X    }
  90. X
  91. X  return result;
  92. X}
  93. X
  94. X/* The numbers 129 and 130 that appear in the fourth element
  95. X   for the context and unidiff entries are used as a way of
  96. X   telling the big switch in `main' how to process those options.  */
  97. X
  98. Xstatic struct option longopts[] =
  99. X{
  100. X  {"ignore-blank-lines", 0, 0, 'B'},
  101. X  {"context", 2, 0, 129},
  102. X  {"ifdef", 1, 0, 'D'},
  103. X  {"show-function-line", 1, 0, 'F'},
  104. X  {"speed-large-files", 0, 0, 'H'},
  105. X  {"ignore-matching-lines", 1, 0, 'I'},
  106. X  {"file-label", 1, 0, 'L'},
  107. X  {"entire-new-files", 0, 0, 'N'},
  108. X  {"new-files", 0, 0, 'N'},
  109. X  {"starting-file", 1, 0, 'S'},
  110. X  {"initial-tab", 0, 0, 'T'},
  111. X  {"text", 0, 0, 'a'},
  112. X  {"all-text", 0, 0, 'a'},
  113. X  {"ascii", 0, 0, 'a'},
  114. X  {"ignore-space-change", 0, 0, 'b'},
  115. X  {"minimal", 0, 0, 'd'},
  116. X  {"ed", 0, 0, 'e'},
  117. X  {"reversed-ed", 0, 0, 'f'},
  118. X  {"ignore-case", 0, 0, 'i'},
  119. X  {"print", 0, 0, 'l'},
  120. X  {"rcs", 0, 0, 'n'},
  121. X  {"show-c-function", 0, 0, 'p'},
  122. X  {"binary", 0, 0, 'q'},
  123. X  {"brief", 0, 0, 'q'},
  124. X  {"recursive", 0, 0, 'r'},
  125. X  {"report-identical-files", 0, 0, 's'},
  126. X  {"expand-tabs", 0, 0, 't'},
  127. X  {"ignore-all-space", 0, 0, 'w'},
  128. X  {"unified", 2, 0, 130},
  129. X  {"version", 0, 0, 'v'},
  130. X  {0, 0, 0, 0}
  131. X};
  132. X
  133. Xmain (argc, argv)
  134. X     int argc;
  135. X     char *argv[];
  136. X{
  137. X  int val;
  138. X  int c;
  139. X  int prev = -1;
  140. X  int longind;
  141. X  extern char *version_string;
  142. X
  143. X  program = argv[0];
  144. X
  145. X  /* Do our initializations. */
  146. X  output_style = OUTPUT_NORMAL;
  147. X  always_text_flag = FALSE;
  148. X  ignore_space_change_flag = FALSE;
  149. X  ignore_all_space_flag = FALSE;
  150. X  length_varies = FALSE;
  151. X  ignore_case_flag = FALSE;
  152. X  ignore_blank_lines_flag = FALSE;
  153. X  ignore_regexp = 0;
  154. X  function_regexp = 0;
  155. X  print_file_same_flag = FALSE;
  156. X  entire_new_file_flag = FALSE;
  157. X  no_details_flag = FALSE;
  158. X  context = -1;
  159. X  line_end_char = '\n';
  160. X  tab_align_flag = FALSE;
  161. X  tab_expand_flag = FALSE;
  162. X  recursive = FALSE;
  163. X  paginate_flag = FALSE;
  164. X  ifdef_string = NULL;
  165. X  heuristic = FALSE;
  166. X  dir_start_file = NULL;
  167. X  msg_chain = NULL;
  168. X  msg_chain_end = NULL;
  169. X  no_discards = 0;
  170. X
  171. X  /* Decode the options.  */
  172. X
  173. X  while ((c = getopt_long (argc, argv,
  174. X               "0123456789abBcC:dD:efF:hHiI:lL:nNpqrsS:tTuvw",
  175. X               longopts, &longind)) != EOF)
  176. X    {
  177. X      if (c == 0)        /* Long option. */
  178. X    c = longopts[longind].val;
  179. X      switch (c)
  180. X    {
  181. X      /* All digits combine in decimal to specify the context-size.  */
  182. X    case '1':
  183. X    case '2':
  184. X    case '3':
  185. X    case '4':
  186. X    case '5':
  187. X    case '6':
  188. X    case '7':
  189. X    case '8':
  190. X    case '9':
  191. X    case '0':
  192. X      if (context == -1)
  193. X        context = 0;
  194. X      /* If a context length has already been specified,
  195. X         more digits allowed only if they follow right after the others.
  196. X         Reject two separate runs of digits, or digits after -C.  */
  197. X      else if (prev < '0' || prev > '9')
  198. X        fatal ("context length specified twice");
  199. X
  200. X      context = context * 10 + c - '0';
  201. X      break;
  202. X
  203. X    case 'a':
  204. X      /* Treat all files as text files; never treat as binary.  */
  205. X      always_text_flag = 1;
  206. X      break;
  207. X
  208. X    case 'b':
  209. X      /* Ignore changes in amount of whitespace.  */
  210. X      ignore_space_change_flag = 1;
  211. X      length_varies = 1;
  212. X      break;
  213. X
  214. X    case 'B':
  215. X      /* Ignore changes affecting only blank lines.  */
  216. X      ignore_blank_lines_flag = 1;
  217. X      break;
  218. X
  219. X    case 'C':
  220. X    case 129:        /* +context[=lines] */
  221. X    case 130:        /* +unified[=lines] */
  222. X      if (optarg)
  223. X        {
  224. X          if (context >= 0)
  225. X        fatal ("context length specified twice");
  226. X          {
  227. X        char *p;
  228. X        for (p = optarg; *p; p++)
  229. X          if (*p < '0' || *p > '9')
  230. X            fatal ("invalid context length argument");
  231. X          }
  232. X          context = atoi (optarg);
  233. X        }
  234. X
  235. X      /* Falls through.  */
  236. X    case 'c':
  237. X      /* Make context-style output.  */
  238. X      specify_style (c == 130 ? OUTPUT_UNIFIED : OUTPUT_CONTEXT);
  239. X      break;
  240. X
  241. X    case 'd':
  242. X      /* Don't discard lines.  This makes things slower (sometimes much
  243. X         slower) but will find a guaranteed minimal set of changes.  */
  244. X      no_discards = 1;
  245. X      break;
  246. X
  247. X    case 'D':
  248. X      /* Make merged #ifdef output.  */
  249. X      specify_style (OUTPUT_IFDEF);
  250. X      ifdef_string = optarg;
  251. X      break;
  252. X
  253. X    case 'e':
  254. X      /* Make output that is a valid `ed' script.  */
  255. X      specify_style (OUTPUT_ED);
  256. X      break;
  257. X
  258. X    case 'f':
  259. X      /* Make output that looks vaguely like an `ed' script
  260. X         but has changes in the order they appear in the file.  */
  261. X      specify_style (OUTPUT_FORWARD_ED);
  262. X      break;
  263. X
  264. X    case 'F':
  265. X      /* Show, for each set of changes, the previous line that
  266. X         matches the specified regexp.  Currently affects only
  267. X         context-style output.  */
  268. X      function_regexp = optarg;
  269. X      break;
  270. X
  271. X    case 'h':
  272. X      /* Split the files into chunks of around 1500 lines
  273. X         for faster processing.  Usually does not change the result.
  274. X
  275. X         This currently has no effect.  */
  276. X      break;
  277. X
  278. X    case 'H':
  279. X      /* Turn on heuristics that speed processing of large files
  280. X         with a small density of changes.  */
  281. X      heuristic = 1;
  282. X      break;
  283. X
  284. X    case 'i':
  285. X      /* Ignore changes in case.  */
  286. X      ignore_case_flag = 1;
  287. X      break;
  288. X
  289. X    case 'I':
  290. X      /* Ignore changes affecting only lines that match the
  291. X         specified regexp.  */
  292. X      ignore_regexp = optarg;
  293. X      break;
  294. X
  295. X    case 'l':
  296. X      /* Pass the output through `pr' to paginate it.  */
  297. X      paginate_flag = 1;
  298. X      break;
  299. X
  300. X    case 'L':
  301. X      /* Specify file labels for `-c' output headers.  */
  302. X      if (!file_label[0])
  303. X        file_label[0] = optarg;
  304. X      else if (!file_label[1])
  305. X        file_label[1] = optarg;
  306. X      else
  307. X        fatal ("too many file label options");
  308. X      break;
  309. X
  310. X    case 'n':
  311. X      /* Output RCS-style diffs, like `-f' except that each command
  312. X         specifies the number of lines affected.  */
  313. X      specify_style (OUTPUT_RCS);
  314. X      break;
  315. X
  316. X    case 'N':
  317. X      /* When comparing directories, if a file appears only in one
  318. X         directory, treat it as present but empty in the other.  */
  319. X      entire_new_file_flag = 1;
  320. X      break;
  321. X
  322. X    case 'p':
  323. X      /* Make context-style output and show name of last C function.  */
  324. X      specify_style (OUTPUT_CONTEXT);
  325. X      function_regexp = "^[_a-zA-Z]";
  326. X      break;
  327. X
  328. X    case 'q':
  329. X      no_details_flag = 1;
  330. X      break;
  331. X
  332. X    case 'r':
  333. X      /* When comparing directories, 
  334. X         recursively compare any subdirectories found.  */
  335. X      recursive = 1;
  336. X      break;
  337. X
  338. X    case 's':
  339. X      /* Print a message if the files are the same.  */
  340. X      print_file_same_flag = 1;
  341. X      break;
  342. X
  343. X    case 'S':
  344. X      /* When comparing directories, start with the specified
  345. X         file name.  This is used for resuming an aborted comparison.  */
  346. X      dir_start_file = optarg;
  347. X      break;
  348. X
  349. X    case 't':
  350. X      /* Expand tabs to spaces in the output so that it preserves
  351. X         the alignment of the input files.  */
  352. X      tab_expand_flag = 1;
  353. X      break;
  354. X
  355. X    case 'T':
  356. X      /* Use a tab in the output, rather than a space, before the
  357. X         text of an input line, so as to keep the proper alignment
  358. X         in the input line without changing the characters in it.  */
  359. X      tab_align_flag = 1;
  360. X      break;
  361. X
  362. X    case 'v':
  363. X      printf ("GNU diff version %s\n", version_string);
  364. X      break;
  365. X
  366. X    case 'u':
  367. X      /* Output the context diff in unidiff format.  */
  368. X      specify_style (OUTPUT_UNIFIED);
  369. X      break;
  370. X
  371. X    case 'w':
  372. X      /* Ignore horizontal whitespace when comparing lines.  */
  373. X      ignore_all_space_flag = 1;
  374. X      length_varies = 1;
  375. X      break;
  376. X
  377. X    default:
  378. X      usage ();
  379. X    }
  380. X      prev = c;
  381. X    }
  382. X
  383. X  if (optind != argc - 2)
  384. X    usage ();
  385. X
  386. X  if (ignore_regexp)
  387. X    {
  388. X      char *val;
  389. X      bzero (&ignore_regexp_compiled, sizeof ignore_regexp_compiled);
  390. X      val = re_compile_pattern (ignore_regexp, strlen (ignore_regexp),
  391. X                &ignore_regexp_compiled);
  392. X      if (val != 0)
  393. X    error ("%s: %s", ignore_regexp, val);
  394. X      ignore_regexp_compiled.fastmap = (char *) xmalloc (256);
  395. X    }
  396. X
  397. X  if (function_regexp)
  398. X    {
  399. X      char *val;
  400. X      bzero (&function_regexp_compiled, sizeof function_regexp_compiled);
  401. X      val = re_compile_pattern (function_regexp, strlen (function_regexp),
  402. X                &function_regexp_compiled);
  403. X      if (val != 0)
  404. X    error ("%s: %s", function_regexp, val);
  405. X      function_regexp_compiled.fastmap = (char *) xmalloc (256);
  406. X    }
  407. X
  408. X  if (output_style != OUTPUT_CONTEXT && output_style != OUTPUT_UNIFIED)
  409. X    context = 0;
  410. X  else if (context == -1)
  411. X    /* Default amount of context for -c.  */
  412. X    context = 3;
  413. X
  414. X  switch_string = option_list (argv + 1, optind - 1);
  415. X
  416. X  val = compare_files (0, argv[optind], 0, argv[optind + 1], 0);
  417. X
  418. X  /* Print any messages that were saved up for last.  */
  419. X  print_message_queue ();
  420. X
  421. X  if (ferror (stdout) || fclose (stdout) != 0)
  422. X    fatal ("write error");
  423. X  exit (val);
  424. X}
  425. X
  426. Xusage ()
  427. X{
  428. X  fprintf (stderr, "\
  429. XUsage: diff [-#] [-abBcdefhHilnNprstTuvw] [-C lines] [-F regexp] [-I regexp]\n\
  430. X       [-L label [-L label]] [-S file] [-D symbol] [+ignore-blank-lines]\n\
  431. X       [+context[=lines]] [+unified[=lines]] [+ifdef=symbol]\n\
  432. X       [+show-function-line=regexp]\n");
  433. X  fprintf (stderr, "\
  434. X       [+speed-large-files] [+ignore-matching-lines=regexp] [+new-file]\n\
  435. X       [+initial-tab] [+starting-file=file] [+text] [+all-text] [+ascii]\n\
  436. X       [+minimal] [+ignore-space-change] [+ed] [+reversed-ed] [+ignore-case]\n");
  437. X  fprintf (stderr, "\
  438. X       [+print] [+rcs] [+show-c-function] [+binary] [+brief] [+recursive]\n\
  439. X       [+report-identical-files] [+expand-tabs] [+ignore-all-space]\n\
  440. X       [+file-label=label [+file-label=label]] [+version] path1 path2\n");
  441. X  exit (2);
  442. X} 
  443. X
  444. Xspecify_style (style)
  445. X     enum output_style style;
  446. X{
  447. X  if (output_style != OUTPUT_NORMAL
  448. X      && output_style != style)
  449. X    error ("conflicting specifications of output style");
  450. X  output_style = style;
  451. X}
  452. X
  453. X/* Compare two files (or dirs) with specified names
  454. X   DIR0/NAME0 and DIR1/NAME1, at level DEPTH in directory recursion.
  455. X   (if DIR0 is 0, then the name is just NAME0, etc.)
  456. X   This is self-contained; it opens the files and closes them.
  457. X
  458. X   Value is 0 if files are identical, 1 if different,
  459. X   2 if there is a problem opening them.  */
  460. X
  461. Xint
  462. Xcompare_files (dir0, name0, dir1, name1, depth)
  463. X     char *dir0, *dir1;
  464. X     char *name0, *name1;
  465. X     int depth;
  466. X{
  467. X  static char Standard_Input[] = "Standard Input";
  468. X  struct file_data inf[2];
  469. X  register int i;
  470. X  int val;
  471. X  int errorcount = 0;
  472. X  int stat_result[2];
  473. X
  474. X  /* If this is directory comparison, perhaps we have a file
  475. X     that exists only in one of the directories.
  476. X     If so, just print a message to that effect.  */
  477. X
  478. X  if (! entire_new_file_flag && (name0 == 0 || name1 == 0))
  479. X    {
  480. X      char *name = name0 == 0 ? name1 : name0;
  481. X      char *dir = name0 == 0 ? dir1 : dir0;
  482. X      message ("Only in %s: %s\n", dir, name);
  483. X      /* Return 1 so that diff_dirs will return 1 ("some files differ").  */
  484. X      return 1;
  485. X    }
  486. X
  487. X  /* Mark any nonexistent file with -1 in the desc field.  */
  488. X  /* Mark unopened files (i.e. directories) with -2. */
  489. X
  490. X  inf[0].desc = name0 == 0 ? -1 : -2;
  491. X  inf[1].desc = name1 == 0 ? -1 : -2;
  492. X
  493. X  /* Now record the full name of each file, including nonexistent ones.  */
  494. X
  495. X  if (name0 == 0)
  496. X    name0 = name1;
  497. X  if (name1 == 0)
  498. X    name1 = name0;
  499. X
  500. X  inf[0].name = dir0 == 0 ? name0 : concat (dir0, "/", name0);
  501. X  inf[1].name = dir1 == 0 ? name1 : concat (dir1, "/", name1);
  502. X
  503. X  /* Stat the files.  Record whether they are directories.
  504. X     Record in stat_result whether stat fails.  */
  505. X
  506. X  for (i = 0; i <= 1; i++)
  507. X    {
  508. X      bzero (&inf[i].stat, sizeof(struct stat));
  509. X      inf[i].dir_p = 0;
  510. X      stat_result[i] = 0;
  511. X
  512. X      if (inf[i].desc != -1)
  513. X    {
  514. X      char *filename = inf[i].name;
  515. X
  516. X      stat_result[i] = 
  517. X        strcmp (filename, "-")
  518. X          ? stat (filename, &inf[i].stat)
  519. X          : fstat (0, &inf[i].stat);
  520. X          
  521. X      if (stat_result[i] < 0)
  522. X        {
  523. X          perror_with_name (filename);
  524. X          errorcount = 1;
  525. X        }
  526. X      else
  527. X        inf[i].dir_p = 
  528. X          S_IFDIR == (inf[i].stat.st_mode & S_IFMT)
  529. X          && strcmp (filename, "-");
  530. X    }
  531. X    }
  532. X
  533. X  /* See if the two named files are actually the same physical file.
  534. X     If so, we know they are identical without actually reading them.  */
  535. X
  536. X  if (output_style != OUTPUT_IFDEF
  537. X      && inf[0].stat.st_ino == inf[1].stat.st_ino
  538. X      && inf[0].stat.st_dev == inf[1].stat.st_dev
  539. X      && stat_result[0] == 0
  540. X      && stat_result[1] == 0)
  541. X    {
  542. X      val = 0;
  543. X      goto done;
  544. X    }
  545. X
  546. X  if (name0 == 0)
  547. X    inf[0].dir_p = inf[1].dir_p;
  548. X  if (name1 == 0)
  549. X    inf[1].dir_p = inf[0].dir_p;
  550. X
  551. X  /* Open the files and record their descriptors.  */
  552. X
  553. X  for (i = 0; i <= 1; i++)
  554. X    {
  555. X      if (inf[i].desc == -1)
  556. X    ;
  557. X      else if (!strcmp (inf[i].name, "-"))
  558. X    {
  559. X      inf[i].desc = 0;
  560. X      inf[i].name = Standard_Input;
  561. X    }
  562. X      /* Don't bother opening if stat already failed.  */
  563. X      else if (stat_result[i] == 0 && ! inf[i].dir_p)
  564. X    {
  565. X      char *filename = inf[i].name;
  566. X
  567. X      inf[i].desc = open (filename, O_RDONLY, 0);
  568. X      if (0 > inf[i].desc)
  569. X        {
  570. X          perror_with_name (filename);
  571. X          errorcount = 1;
  572. X        }
  573. X    }
  574. X    }
  575. X
  576. X  if (errorcount)
  577. X    {
  578. X
  579. X      /* If either file should exist but fails to be opened, return 2.  */
  580. X
  581. X      val = 2;
  582. X
  583. X    }
  584. X  else if (inf[0].dir_p && inf[1].dir_p)
  585. X    {
  586. X      if (output_style == OUTPUT_IFDEF)
  587. X    fatal ("-D option not supported with directories");
  588. X
  589. X      /* If both are directories, compare the files in them.  */
  590. X
  591. X      if (depth > 0 && !recursive)
  592. X    {
  593. X      /* But don't compare dir contents one level down
  594. X         unless -r was specified.  */
  595. X      message ("Common subdirectories: %s and %s\n",
  596. X           inf[0].name, inf[1].name);
  597. X      val = 0;
  598. X    }
  599. X      else
  600. X    {
  601. X      val = diff_dirs (inf[0].name, inf[1].name, 
  602. X               compare_files, depth, 0, 0);
  603. X    }
  604. X
  605. X    }
  606. X  else if (depth == 0 && (inf[0].dir_p || inf[1].dir_p))
  607. X    {
  608. X
  609. X      /* If only one is a directory, and it was specified in the command line,
  610. X     use the file in that dir whose basename matches the other file.  */
  611. X
  612. X      int dir_arg = (inf[0].dir_p ? 0 : 1);
  613. X      int fnm_arg = (inf[0].dir_p ? 1 : 0);
  614. X      char *p = rindex (inf[fnm_arg].name, '/');
  615. X      char *filename = concat (inf[dir_arg].name,  "/",
  616. X                   (p ? p+1 : inf[fnm_arg].name));
  617. X
  618. X      if (inf[fnm_arg].name == Standard_Input)
  619. X    fatal ("can't compare - to a directory");
  620. X
  621. X      inf[dir_arg].desc = open (filename, O_RDONLY, 0);
  622. X
  623. X      if (0 > inf[dir_arg].desc)
  624. X    {
  625. X      perror_with_name (filename);
  626. X      val = 2;
  627. X    }
  628. X      else
  629. X    {
  630. X      /* JF: patch from the net to check and make sure we can really free
  631. X         this.  If it's from argv[], freeing it is a *really* bad idea */
  632. X      if (0 != (dir_arg ? dir1 : dir0))
  633. X        free (inf[dir_arg].name);
  634. X      inf[dir_arg].name = filename;
  635. X      if (fstat (inf[dir_arg].desc, &inf[dir_arg].stat) < 0)
  636. X        pfatal_with_name (inf[dir_arg].name);
  637. X
  638. X      inf[dir_arg].dir_p
  639. X        = (S_IFDIR == (inf[dir_arg].stat.st_mode & S_IFMT));
  640. X      if (inf[dir_arg].dir_p)
  641. X        {
  642. X          error ("%s is a directory but %s is not",
  643. X             inf[dir_arg].name, inf[fnm_arg].name);
  644. X          val = 1;
  645. X        }
  646. X      else
  647. X        val = diff_2_files (inf, depth);
  648. X    }
  649. X
  650. X    }
  651. X  else if (depth > 0 && (inf[0].dir_p || inf[1].dir_p))
  652. X    {
  653. X      /* Perhaps we have a subdirectory that exists only in one directory.
  654. X     If so, just print a message to that effect.  */
  655. X
  656. X      if (inf[0].desc == -1 || inf[1].desc == -1)
  657. X    {
  658. X      if (entire_new_file_flag && recursive)
  659. X        val = diff_dirs (inf[0].name, inf[1].name, compare_files, depth,
  660. X                 inf[0].desc == -1, inf[1].desc == -1);
  661. X      else
  662. X        {
  663. X          char *dir = (inf[0].desc == -1) ? dir1 : dir0;
  664. X          message ("Only in %s: %s\n", dir, name0);
  665. X          val = 1;
  666. X        }
  667. X    }
  668. X      else
  669. X    {
  670. X      /* We have a subdirectory in one directory
  671. X         and a file in the other.  */
  672. X
  673. X      if (inf[0].dir_p)
  674. X        message ("%s is a directory but %s is not\n",
  675. X             inf[0].name, inf[1].name);
  676. X      else
  677. X        message ("%s is a directory but %s is not\n",
  678. X             inf[1].name, inf[0].name);
  679. X      /* This is a difference.  */
  680. X      val = 1;
  681. X    }
  682. X    }
  683. X  else
  684. X    {
  685. X
  686. X      /* Both exist and both are ordinary files.  */
  687. X
  688. X      val = diff_2_files (inf, depth);
  689. X
  690. X    }
  691. X
  692. X  /* Now the comparison has been done, if no error prevented it,
  693. X     and VAL is the value this function will return.  */
  694. X
  695. X  if (inf[0].desc >= 0)
  696. X    close (inf[0].desc);
  697. X  if (inf[1].desc >= 0)
  698. X    close (inf[1].desc);
  699. X
  700. X done:
  701. X  if (val == 0 && !inf[0].dir_p)
  702. X    {
  703. X      if (print_file_same_flag)
  704. X    message ("Files %s and %s are identical\n",
  705. X         inf[0].name, inf[1].name);
  706. X    }
  707. X  else
  708. X    fflush (stdout);
  709. X
  710. X  if (dir0 != 0)
  711. X    free (inf[0].name);
  712. X  if (dir1 != 0)
  713. X    free (inf[1].name);
  714. X
  715. X  return val;
  716. X}
  717. END_OF_FILE
  718. if test 17901 -ne `wc -c <'diff.c'`; then
  719.     echo shar: \"'diff.c'\" unpacked with wrong size!
  720. fi
  721. # end of 'diff.c'
  722. fi
  723. if test -f 'getopt.c' -a "${1}" != "-c" ; then 
  724.   echo shar: Will not clobber existing file \"'getopt.c'\"
  725. else
  726. echo shar: Extracting \"'getopt.c'\" \(16740 characters\)
  727. sed "s/^X//" >'getopt.c' <<'END_OF_FILE'
  728. X/* Getopt for GNU.
  729. X   Copyright (C) 1987, 1989, 1990 Free Software Foundation, Inc.
  730. X
  731. X   This program is free software; you can redistribute it and/or modify
  732. X   it under the terms of the GNU General Public License as published by
  733. X   the Free Software Foundation; either version 1, or (at your option)
  734. X   any later version.
  735. X
  736. X   This program is distributed in the hope that it will be useful,
  737. X   but WITHOUT ANY WARRANTY; without even the implied warranty of
  738. X   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  739. X   GNU General Public License for more details.
  740. X
  741. X   You should have received a copy of the GNU General Public License
  742. X   along with this program; if not, write to the Free Software
  743. X   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  744. X
  745. X#ifdef __STDC__
  746. X#define CONST const
  747. X#else
  748. X#define CONST
  749. X#endif
  750. X
  751. X/* This version of `getopt' appears to the caller like standard Unix `getopt'
  752. X   but it behaves differently for the user, since it allows the user
  753. X   to intersperse the options with the other arguments.
  754. X
  755. X   As `getopt' works, it permutes the elements of `argv' so that,
  756. X   when it is done, all the options precede everything else.  Thus
  757. X   all application programs are extended to handle flexible argument order.
  758. X
  759. X   Setting the environment variable _POSIX_OPTION_ORDER disables permutation.
  760. X   Then the behavior is completely standard.
  761. X
  762. X   GNU application programs can use a third alternative mode in which
  763. X   they can distinguish the relative order of options and other arguments.  */
  764. X
  765. X#include <stdio.h>
  766. X
  767. X/* If compiled with GNU C, use the built-in alloca */
  768. X#ifdef __GNUC__
  769. X#define alloca __builtin_alloca
  770. X#else /* not __GNUC__ */
  771. X#ifdef sparc
  772. X#include <alloca.h>
  773. X#else
  774. Xchar *alloca ();
  775. X#endif
  776. X#endif /* not __GNUC__ */
  777. X
  778. X#if defined(STDC_HEADERS) || defined(__GNU_LIBRARY__)
  779. X#include <stdlib.h>
  780. X#include <string.h>
  781. X#define bcopy(s, d, n) memcpy ((d), (s), (n))
  782. X#define index strchr
  783. X#else
  784. X
  785. X#ifdef USG
  786. X#include <string.h>
  787. X#define bcopy(s, d, n) memcpy ((d), (s), (n))
  788. X#define index strchr
  789. X#else
  790. X#ifdef VMS
  791. X#include <string.h>
  792. X#else
  793. X#include <strings.h>
  794. X#endif
  795. Xvoid bcopy ();
  796. X#endif
  797. X
  798. Xchar *getenv ();
  799. Xchar *malloc ();
  800. X#endif
  801. X
  802. X/* For communication from `getopt' to the caller.
  803. X   When `getopt' finds an option that takes an argument,
  804. X   the argument value is returned here.
  805. X   Also, when `ordering' is RETURN_IN_ORDER,
  806. X   each non-option ARGV-element is returned here.  */
  807. X
  808. Xchar *optarg = 0;
  809. X
  810. X/* Index in ARGV of the next element to be scanned.
  811. X   This is used for communication to and from the caller
  812. X   and for communication between successive calls to `getopt'.
  813. X
  814. X   On entry to `getopt', zero means this is the first call; initialize.
  815. X
  816. X   When `getopt' returns EOF, this is the index of the first of the
  817. X   non-option elements that the caller should itself scan.
  818. X
  819. X   Otherwise, `optind' communicates from one call to the next
  820. X   how much of ARGV has been scanned so far.  */
  821. X
  822. Xint optind = 0;
  823. X
  824. X/* The next char to be scanned in the option-element
  825. X   in which the last option character we returned was found.
  826. X   This allows us to pick up the scan where we left off.
  827. X
  828. X   If this is zero, or a null string, it means resume the scan
  829. X   by advancing to the next ARGV-element.  */
  830. X
  831. Xstatic char *nextchar;
  832. X
  833. X/* Callers store zero here to inhibit the error message
  834. X   for unrecognized options.  */
  835. X
  836. Xint opterr = 1;
  837. X
  838. X/* Describe how to deal with options that follow non-option ARGV-elements.
  839. X
  840. X   If the caller did not specify anything,
  841. X   the default is REQUIRE_ORDER if the environment variable
  842. X   _POSIX_OPTION_ORDER is defined, PERMUTE otherwise.
  843. X
  844. X   REQUIRE_ORDER means don't recognize them as options;
  845. X   stop option processing when the first non-option is seen.
  846. X   This is what Unix does.
  847. X   This mode of operation is selected by either setting the environment
  848. X   variable _POSIX_OPTION_ORDER, or using `+' as the first character
  849. X   of the list of option characters.
  850. X
  851. X   PERMUTE is the default.  We permute the contents of ARGV as we scan,
  852. X   so that eventually all the non-options are at the end.  This allows options
  853. X   to be given in any order, even with programs that were not written to
  854. X   expect this.
  855. X
  856. X   RETURN_IN_ORDER is an option available to programs that were written
  857. X   to expect options and other ARGV-elements in any order and that care about
  858. X   the ordering of the two.  We describe each non-option ARGV-element
  859. X   as if it were the argument of an option with character code 1.
  860. X   Using `-' as the first character of the list of option characters
  861. X   selects this mode of operation.
  862. X
  863. X   The special argument `--' forces an end of option-scanning regardless
  864. X   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
  865. X   `--' can cause `getopt' to return EOF with `optind' != ARGC.  */
  866. X
  867. Xstatic enum
  868. X{
  869. X  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
  870. X} ordering;
  871. X
  872. X/* Describe the long-named options requested by the application.
  873. X   _GETOPT_LONG_OPTIONS is a vector of `struct option' terminated by an
  874. X   element containing a name which is zero.
  875. X   The field `has_arg' is 1 if the option takes an argument,
  876. X   2 if it takes an optional argument.  */
  877. X
  878. Xstruct option
  879. X{
  880. X  char *name;
  881. X  int has_arg;
  882. X  int *flag;
  883. X  int val;
  884. X};
  885. X
  886. XCONST struct option *_getopt_long_options;
  887. X
  888. Xint _getopt_long_only = 0;
  889. X
  890. X/* Index in _GETOPT_LONG_OPTIONS of the long-named option actually found.
  891. X   Only valid when a long-named option was found. */
  892. X
  893. Xint option_index;
  894. X
  895. X/* Handle permutation of arguments.  */
  896. X
  897. X/* Describe the part of ARGV that contains non-options that have
  898. X   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
  899. X   `last_nonopt' is the index after the last of them.  */
  900. X
  901. Xstatic int first_nonopt;
  902. Xstatic int last_nonopt;
  903. X
  904. X/* Exchange two adjacent subsequences of ARGV.
  905. X   One subsequence is elements [first_nonopt,last_nonopt)
  906. X    which contains all the non-options that have been skipped so far.
  907. X   The other is elements [last_nonopt,optind), which contains all
  908. X    the options processed since those non-options were skipped.
  909. X
  910. X   `first_nonopt' and `last_nonopt' are relocated so that they describe
  911. X    the new indices of the non-options in ARGV after they are moved.  */
  912. X
  913. Xstatic void
  914. Xexchange (argv)
  915. X     char **argv;
  916. X{
  917. X  int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
  918. X  char **temp = (char **) alloca (nonopts_size);
  919. X
  920. X  /* Interchange the two blocks of data in ARGV.  */
  921. X
  922. X  bcopy (&argv[first_nonopt], temp, nonopts_size);
  923. X  bcopy (&argv[last_nonopt], &argv[first_nonopt],
  924. X     (optind - last_nonopt) * sizeof (char *));
  925. X  bcopy (temp, &argv[first_nonopt + optind - last_nonopt], nonopts_size);
  926. X
  927. X  /* Update records for the slots the non-options now occupy.  */
  928. X
  929. X  first_nonopt += (optind - last_nonopt);
  930. X  last_nonopt = optind;
  931. X}
  932. X
  933. X/* Scan elements of ARGV (whose length is ARGC) for option characters
  934. X   given in OPTSTRING.
  935. X
  936. X   If an element of ARGV starts with '-', and is not exactly "-" or "--",
  937. X   then it is an option element.  The characters of this element
  938. X   (aside from the initial '-') are option characters.  If `getopt'
  939. X   is called repeatedly, it returns successively each of the option characters
  940. X   from each of the option elements.
  941. X
  942. X   If `getopt' finds another option character, it returns that character,
  943. X   updating `optind' and `nextchar' so that the next call to `getopt' can
  944. X   resume the scan with the following option character or ARGV-element.
  945. X
  946. X   If there are no more option characters, `getopt' returns `EOF'.
  947. X   Then `optind' is the index in ARGV of the first ARGV-element
  948. X   that is not an option.  (The ARGV-elements have been permuted
  949. X   so that those that are not options now come last.)
  950. X
  951. X   OPTSTRING is a string containing the legitimate option characters.
  952. X   If an option character is seen that is not listed in OPTSTRING,
  953. X   return '?' after printing an error message.  If you set `opterr' to
  954. X   zero, the error message is suppressed but we still return '?'.
  955. X
  956. X   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
  957. X   so the following text in the same ARGV-element, or the text of the following
  958. X   ARGV-element, is returned in `optarg'.  Two colons mean an option that
  959. X   wants an optional arg; if there is text in the current ARGV-element,
  960. X   it is returned in `optarg', otherwise `optarg' is set to zero.
  961. X
  962. X   If OPTSTRING starts with `-' or `+', it requests different methods of
  963. X   handling the non-option ARGV-elements.
  964. X   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
  965. X
  966. X   Long-named options begin with `+' instead of `-'.
  967. X   Their names may be abbreviated as long as the abbreviation is unique
  968. X   or is an exact match for some defined option.  If they have an
  969. X   argument, it follows the option name in the same ARGV-element, separated
  970. X   from the option name by a `=', or else the in next ARGV-element.
  971. X   When `getopt' finds a long-named option, it returns 0 if that option's
  972. X   `flag' field is nonzero, the value of the option's `val' field
  973. X   otherwise.  */
  974. X
  975. Xint
  976. Xgetopt (argc, argv, optstring)
  977. X     int argc;
  978. X     char **argv;
  979. X     CONST char *optstring;
  980. X{
  981. X  optarg = 0;
  982. X
  983. X  /* Initialize the internal data when the first call is made.
  984. X     Start processing options with ARGV-element 1 (since ARGV-element 0
  985. X     is the program name); the sequence of previously skipped
  986. X     non-option ARGV-elements is empty.  */
  987. X
  988. X  if (optind == 0)
  989. X    {
  990. X      first_nonopt = last_nonopt = optind = 1;
  991. X
  992. X      nextchar = 0;
  993. X
  994. X      /* Determine how to handle the ordering of options and nonoptions.  */
  995. X
  996. X      if (optstring[0] == '-')
  997. X    {
  998. X      ordering = RETURN_IN_ORDER;
  999. X      ++optstring;
  1000. X    }
  1001. X      else if (optstring[0] == '+')
  1002. X    {
  1003. X      ordering = REQUIRE_ORDER;
  1004. X      ++optstring;
  1005. X    }
  1006. X      else if (getenv ("_POSIX_OPTION_ORDER") != 0)
  1007. X    ordering = REQUIRE_ORDER;
  1008. X      else
  1009. X    ordering = PERMUTE;
  1010. X    }
  1011. X
  1012. X  if (nextchar == 0 || *nextchar == 0)
  1013. X    {
  1014. X      if (ordering == PERMUTE)
  1015. X    {
  1016. X      /* If we have just processed some options following some non-options,
  1017. X         exchange them so that the options come first.  */
  1018. X
  1019. X      if (first_nonopt != last_nonopt && last_nonopt != optind)
  1020. X        exchange (argv);
  1021. X      else if (last_nonopt != optind)
  1022. X        first_nonopt = optind;
  1023. X
  1024. X      /* Now skip any additional non-options
  1025. X         and extend the range of non-options previously skipped.  */
  1026. X
  1027. X      while (optind < argc
  1028. X         && (argv[optind][0] != '-'
  1029. X             || argv[optind][1] == 0)
  1030. X         && (_getopt_long_options == 0
  1031. X             || argv[optind][0] != '+'
  1032. X             || argv[optind][1] == 0))
  1033. X        optind++;
  1034. X      last_nonopt = optind;
  1035. X    }
  1036. X
  1037. X      /* Special ARGV-element `--' means premature end of options.
  1038. X     Skip it like a null option,
  1039. X     then exchange with previous non-options as if it were an option,
  1040. X     then skip everything else like a non-option.  */
  1041. X
  1042. X      if (optind != argc && !strcmp (argv[optind], "--"))
  1043. X    {
  1044. X      optind++;
  1045. X
  1046. X      if (first_nonopt != last_nonopt && last_nonopt != optind)
  1047. X        exchange (argv);
  1048. X      else if (first_nonopt == last_nonopt)
  1049. X        first_nonopt = optind;
  1050. X      last_nonopt = argc;
  1051. X
  1052. X      optind = argc;
  1053. X    }
  1054. X
  1055. X      /* If we have done all the ARGV-elements, stop the scan
  1056. X     and back over any non-options that we skipped and permuted.  */
  1057. X
  1058. X      if (optind == argc)
  1059. X    {
  1060. X      /* Set the next-arg-index to point at the non-options
  1061. X         that we previously skipped, so the caller will digest them.  */
  1062. X      if (first_nonopt != last_nonopt)
  1063. X        optind = first_nonopt;
  1064. X      return EOF;
  1065. X    }
  1066. X
  1067. X      /* If we have come to a non-option and did not permute it,
  1068. X     either stop the scan or describe it to the caller and pass it by.  */
  1069. X
  1070. X      if ((argv[optind][0] != '-' || argv[optind][1] == 0)
  1071. X      && (_getopt_long_options == 0
  1072. X          || argv[optind][0] != '+' || argv[optind][1] == 0))
  1073. X    {
  1074. X      if (ordering == REQUIRE_ORDER)
  1075. X        return EOF;
  1076. X      optarg = argv[optind++];
  1077. X      return 1;
  1078. X    }
  1079. X
  1080. X      /* We have found another option-ARGV-element.
  1081. X     Start decoding its characters.  */
  1082. X
  1083. X      nextchar = argv[optind] + 1;
  1084. X    }
  1085. X
  1086. X  if (_getopt_long_options != 0
  1087. X      && (argv[optind][0] == '+'
  1088. X      || (_getopt_long_only && argv[optind][0] == '-'))
  1089. X    )
  1090. X    {
  1091. X      CONST struct option *p;
  1092. X      char *s = nextchar;
  1093. X      int exact = 0;
  1094. X      int ambig = 0;
  1095. X      CONST struct option *pfound = 0;
  1096. X      int indfound;
  1097. X
  1098. X      while (*s && *s != '=')
  1099. X    s++;
  1100. X
  1101. X      /* Test all options for either exact match or abbreviated matches.  */
  1102. X      for (p = _getopt_long_options, option_index = 0; p->name;
  1103. X       p++, option_index++)
  1104. X    if (!strncmp (p->name, nextchar, s - nextchar))
  1105. X      {
  1106. X        if (s - nextchar == strlen (p->name))
  1107. X          {
  1108. X        /* Exact match found.  */
  1109. X        pfound = p;
  1110. X        indfound = option_index;
  1111. X        exact = 1;
  1112. X        break;
  1113. X          }
  1114. X        else if (pfound == 0)
  1115. X          {
  1116. X        /* First nonexact match found.  */
  1117. X        pfound = p;
  1118. X        indfound = option_index;
  1119. X          }
  1120. X        else
  1121. X          /* Second nonexact match found.  */
  1122. X          ambig = 1;
  1123. X      }
  1124. X
  1125. X      if (ambig && !exact)
  1126. X    {
  1127. X      fprintf (stderr, "%s: option `%s' is ambiguous\n",
  1128. X           argv[0], argv[optind]);
  1129. X      nextchar += strlen (nextchar);
  1130. X      optind++;
  1131. X      return '?';
  1132. X    }
  1133. X
  1134. X      if (pfound != 0)
  1135. X    {
  1136. X      option_index = indfound;
  1137. X      optind++;
  1138. X      if (*s)
  1139. X        {
  1140. X          if (pfound->has_arg > 0)
  1141. X        optarg = s + 1;
  1142. X          else
  1143. X        {
  1144. X          fprintf (stderr,
  1145. X               "%s: option `%c%s' doesn't allow an argument\n",
  1146. X               argv[0], argv[optind - 1][0], pfound->name);
  1147. X          nextchar += strlen (nextchar);
  1148. X          return '?';
  1149. X        }
  1150. X        }
  1151. X      else if (pfound->has_arg == 1)
  1152. X        {
  1153. X          if (optind < argc)
  1154. X        optarg = argv[optind++];
  1155. X          else
  1156. X        {
  1157. X          fprintf (stderr, "%s: option `%s' requires an argument\n",
  1158. X               argv[0], argv[optind - 1]);
  1159. X          nextchar += strlen (nextchar);
  1160. X          return '?';
  1161. X        }
  1162. X        }
  1163. X      nextchar += strlen (nextchar);
  1164. X      if (pfound->flag)
  1165. X        {
  1166. X          *(pfound->flag) = pfound->val;
  1167. X          return 0;
  1168. X        }
  1169. X      return pfound->val;
  1170. X    }
  1171. X      /* Can't find it as a long option.  If this is getopt_long_only,
  1172. X     and the option starts with '-' and is a valid short
  1173. X     option, then interpret it as a short option.  Otherwise it's
  1174. X     an error.  */
  1175. X      if (_getopt_long_only == 0 || argv[optind][0] == '+' ||
  1176. X      index (optstring, *nextchar) == 0)
  1177. X    {
  1178. X      if (opterr != 0)
  1179. X        fprintf (stderr, "%s: unrecognized option `%c%s'\n",
  1180. X             argv[0], argv[optind][0], nextchar);
  1181. X      nextchar += strlen (nextchar);
  1182. X      optind++;
  1183. X      return '?';
  1184. X    }
  1185. X    }
  1186. X
  1187. X  /* Look at and handle the next option-character.  */
  1188. X
  1189. X  {
  1190. X    char c = *nextchar++;
  1191. X    char *temp = index (optstring, c);
  1192. X
  1193. X    /* Increment `optind' when we start to process its last character.  */
  1194. X    if (*nextchar == 0)
  1195. X      optind++;
  1196. X
  1197. X    if (temp == 0 || c == ':')
  1198. X      {
  1199. X    if (opterr != 0)
  1200. X      {
  1201. X        if (c < 040 || c >= 0177)
  1202. X          fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
  1203. X               argv[0], c);
  1204. X        else
  1205. X          fprintf (stderr, "%s: unrecognized option `-%c'\n",
  1206. X               argv[0], c);
  1207. X      }
  1208. X    return '?';
  1209. X      }
  1210. X    if (temp[1] == ':')
  1211. X      {
  1212. X    if (temp[2] == ':')
  1213. X      {
  1214. X        /* This is an option that accepts an argument optionally.  */
  1215. X        if (*nextchar != 0)
  1216. X          {
  1217. X        optarg = nextchar;
  1218. X        optind++;
  1219. X          }
  1220. X        else
  1221. X          optarg = 0;
  1222. X        nextchar = 0;
  1223. X      }
  1224. X    else
  1225. X      {
  1226. X        /* This is an option that requires an argument.  */
  1227. X        if (*nextchar != 0)
  1228. X          {
  1229. X        optarg = nextchar;
  1230. X        /* If we end this ARGV-element by taking the rest as an arg,
  1231. X           we must advance to the next element now.  */
  1232. X        optind++;
  1233. X          }
  1234. X        else if (optind == argc)
  1235. X          {
  1236. X        if (opterr != 0)
  1237. X          fprintf (stderr, "%s: option `-%c' requires an argument\n",
  1238. X               argv[0], c);
  1239. X        c = '?';
  1240. X          }
  1241. X        else
  1242. X          /* We already incremented `optind' once;
  1243. X         increment it again when taking next ARGV-elt as argument.  */
  1244. X          optarg = argv[optind++];
  1245. X        nextchar = 0;
  1246. X      }
  1247. X      }
  1248. X    return c;
  1249. X  }
  1250. X}
  1251. X
  1252. X#ifdef TEST
  1253. X
  1254. X/* Compile with -DTEST to make an executable for use in testing
  1255. X   the above definition of `getopt'.  */
  1256. X
  1257. Xint
  1258. Xmain (argc, argv)
  1259. X     int argc;
  1260. X     char **argv;
  1261. X{
  1262. X  int c;
  1263. X  int digit_optind = 0;
  1264. X
  1265. X  while (1)
  1266. X    {
  1267. X      int this_option_optind = optind ? optind : 1;
  1268. X
  1269. X      c = getopt (argc, argv, "abc:d:0123456789");
  1270. X      if (c == EOF)
  1271. X    break;
  1272. X
  1273. X      switch (c)
  1274. X    {
  1275. X    case '0':
  1276. X    case '1':
  1277. X    case '2':
  1278. X    case '3':
  1279. X    case '4':
  1280. X    case '5':
  1281. X    case '6':
  1282. X    case '7':
  1283. X    case '8':
  1284. X    case '9':
  1285. X      if (digit_optind != 0 && digit_optind != this_option_optind)
  1286. X        printf ("digits occur in two different argv-elements.\n");
  1287. X      digit_optind = this_option_optind;
  1288. X      printf ("option %c\n", c);
  1289. X      break;
  1290. X
  1291. X    case 'a':
  1292. X      printf ("option a\n");
  1293. X      break;
  1294. X
  1295. X    case 'b':
  1296. X      printf ("option b\n");
  1297. X      break;
  1298. X
  1299. X    case 'c':
  1300. X      printf ("option c with value `%s'\n", optarg);
  1301. X      break;
  1302. X
  1303. X    case '?':
  1304. X      break;
  1305. X
  1306. X    default:
  1307. X      printf ("?? getopt returned character code 0%o ??\n", c);
  1308. X    }
  1309. X    }
  1310. X
  1311. X  if (optind < argc)
  1312. X    {
  1313. X      printf ("non-option ARGV-elements: ");
  1314. X      while (optind < argc)
  1315. X    printf ("%s ", argv[optind++]);
  1316. X      printf ("\n");
  1317. X    }
  1318. X
  1319. X  exit (0);
  1320. X}
  1321. X
  1322. X#endif /* TEST */
  1323. END_OF_FILE
  1324. if test 16740 -ne `wc -c <'getopt.c'`; then
  1325.     echo shar: \"'getopt.c'\" unpacked with wrong size!
  1326. fi
  1327. # end of 'getopt.c'
  1328. fi
  1329. if test -f 'util.c' -a "${1}" != "-c" ; then 
  1330.   echo shar: Will not clobber existing file \"'util.c'\"
  1331. else
  1332. echo shar: Extracting \"'util.c'\" \(14888 characters\)
  1333. sed "s/^X//" >'util.c' <<'END_OF_FILE'
  1334. X/* Support routines for GNU DIFF.
  1335. X   Copyright (C) 1988, 1989 Free Software Foundation, Inc.
  1336. X
  1337. XThis file is part of GNU DIFF.
  1338. X
  1339. XGNU DIFF is free software; you can redistribute it and/or modify
  1340. Xit under the terms of the GNU General Public License as published by
  1341. Xthe Free Software Foundation; either version 1, or (at your option)
  1342. Xany later version.
  1343. X
  1344. XGNU DIFF is distributed in the hope that it will be useful,
  1345. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  1346. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  1347. XGNU General Public License for more details.
  1348. X
  1349. XYou should have received a copy of the GNU General Public License
  1350. Xalong with GNU DIFF; see the file COPYING.  If not, write to
  1351. Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  1352. X
  1353. X#include "diff.h"
  1354. X
  1355. X/* Use when a system call returns non-zero status.
  1356. X   TEXT should normally be the file name.  */
  1357. X
  1358. Xvoid
  1359. Xperror_with_name (text)
  1360. X     char *text;
  1361. X{
  1362. X  fprintf (stderr, "%s: ", program);
  1363. X  perror (text);
  1364. X}
  1365. X
  1366. X/* Use when a system call returns non-zero status and that is fatal.  */
  1367. X
  1368. Xvoid
  1369. Xpfatal_with_name (text)
  1370. X     char *text;
  1371. X{
  1372. X  print_message_queue ();
  1373. X  fprintf (stderr, "%s: ", program);
  1374. X  perror (text);
  1375. X  exit (2);
  1376. X}
  1377. X
  1378. X/* Print an error message from the format-string FORMAT
  1379. X   with args ARG1 and ARG2.  */
  1380. X
  1381. Xvoid
  1382. Xerror (format, arg, arg1)
  1383. X     char *format;
  1384. X     char *arg;
  1385. X     char *arg1;
  1386. X{
  1387. X  fprintf (stderr, "%s: ", program);
  1388. X  fprintf (stderr, format, arg, arg1);
  1389. X  fprintf (stderr, "\n");
  1390. X}
  1391. X
  1392. X/* Print an error message containing the string TEXT, then exit.  */
  1393. X
  1394. Xvoid
  1395. Xfatal (message)
  1396. X     char *message;
  1397. X{
  1398. X  print_message_queue ();
  1399. X  error (message, "");
  1400. X  exit (2);
  1401. X}
  1402. X
  1403. X/* Like printf, except if -l in effect then save the message and print later.
  1404. X   This is used for things like "binary files differ" and "Only in ...".  */
  1405. X
  1406. Xvoid
  1407. Xmessage (format, arg1, arg2)
  1408. X     char *format, *arg1, *arg2;
  1409. X{
  1410. X  if (paginate_flag)
  1411. X    {
  1412. X      struct msg *new = (struct msg *) xmalloc (sizeof (struct msg));
  1413. X      if (msg_chain_end == 0)
  1414. X    msg_chain = msg_chain_end = new;
  1415. X      else
  1416. X    {
  1417. X      msg_chain_end->next = new;
  1418. X      msg_chain_end = new;
  1419. X    }
  1420. X      new->format = format;
  1421. X      new->arg1 = concat (arg1, "", "");
  1422. X      new->arg2 = concat (arg2, "", "");
  1423. X      new->next = 0;
  1424. X    }
  1425. X  else
  1426. X    printf (format, arg1, arg2);
  1427. X}
  1428. X
  1429. X/* Output all the messages that were saved up by calls to `message'.  */
  1430. X
  1431. Xvoid
  1432. Xprint_message_queue ()
  1433. X{
  1434. X  struct msg *m;
  1435. X
  1436. X  for (m = msg_chain; m; m = m->next)
  1437. X    printf (m->format, m->arg1, m->arg2);
  1438. X}
  1439. X
  1440. X/* Call before outputting the results of comparing files NAME0 and NAME1
  1441. X   to set up OUTFILE, the stdio stream for the output to go to.
  1442. X
  1443. X   Usually, OUTFILE is just stdout.  But when -l was specified
  1444. X   we fork off a `pr' and make OUTFILE a pipe to it.
  1445. X   `pr' then outputs to our stdout.  */
  1446. X
  1447. Xvoid
  1448. Xsetup_output (name0, name1, depth)
  1449. X     char *name0, *name1;
  1450. X     int depth;
  1451. X{
  1452. X  char *name;
  1453. X
  1454. X  /* Construct the header of this piece of diff.  */
  1455. X  name = (char *) xmalloc (strlen (name0) + strlen (name1)
  1456. X               + strlen (switch_string) + 15);
  1457. X
  1458. X  strcpy (name, "diff");
  1459. X  strcat (name, switch_string);
  1460. X  strcat (name, " ");
  1461. X  strcat (name, name0);
  1462. X  strcat (name, " ");
  1463. X  strcat (name, name1);
  1464. X
  1465. X  if (paginate_flag)
  1466. X    {
  1467. X      int pipes[2];
  1468. X      int desc;
  1469. X
  1470. X      /* For a `pr' and make OUTFILE a pipe to it.  */
  1471. X      if (pipe (pipes) < 0)
  1472. X    pfatal_with_name ("pipe");
  1473. X
  1474. X      fflush (stdout);
  1475. X
  1476. X      desc = vfork ();
  1477. X      if (desc < 0)
  1478. X    pfatal_with_name ("vfork");
  1479. X
  1480. X      if (desc == 0)
  1481. X    {
  1482. X      close (pipes[1]);
  1483. X      if (pipes[0] != fileno (stdin))
  1484. X        {
  1485. X          if (dup2 (pipes[0], fileno (stdin)) < 0)
  1486. X        pfatal_with_name ("dup2");
  1487. X          close (pipes[0]);
  1488. X        }
  1489. X
  1490. X      if (execl (PR_FILE_NAME, PR_FILE_NAME, "-f", "-h", name, 0) < 0)
  1491. X        pfatal_with_name (PR_FILE_NAME);
  1492. X    }
  1493. X      else
  1494. X    {
  1495. X      close (pipes[0]);
  1496. X      outfile = fdopen (pipes[1], "w");
  1497. X    } 
  1498. X    }
  1499. X  else
  1500. X    {
  1501. X
  1502. X      /* If -l was not specified, output the diff straight to `stdout'.  */
  1503. X
  1504. X      outfile = stdout;
  1505. X
  1506. X      /* If handling multiple files (because scanning a directory),
  1507. X     print which files the following output is about.  */
  1508. X      if (depth > 0)
  1509. X    printf ("%s\n", name);
  1510. X    }
  1511. X
  1512. X  free (name);
  1513. X}
  1514. X
  1515. X/* Call after the end of output of diffs for one file.
  1516. X   Close OUTFILE and get rid of the `pr' subfork.  */
  1517. X
  1518. Xvoid
  1519. Xfinish_output ()
  1520. X{
  1521. X  if (outfile != stdout)
  1522. X    {
  1523. X      fclose (outfile);
  1524. X      wait (0);
  1525. X    }
  1526. X}
  1527. X
  1528. X/* Compare two lines (typically one from each input file)
  1529. X   according to the command line options.
  1530. X   Each line is described by a `struct line_def'.
  1531. X   Return 1 if the lines differ, like `bcmp'.  */
  1532. X
  1533. Xint
  1534. Xline_cmp (s1, s2)
  1535. X     struct line_def *s1, *s2;
  1536. X{
  1537. X  register char *t1, *t2;
  1538. X  register char end_char = line_end_char;
  1539. X  int savechar;
  1540. X
  1541. X  /* Check first for exact identity.
  1542. X     If that is true, return 0 immediately.
  1543. X     This detects the common case of exact identity
  1544. X     faster than complete comparison would.  */
  1545. X
  1546. X  t1 = s1->text;
  1547. X  t2 = s2->text;
  1548. X
  1549. X  /* Alter the character following line 2 so it doesn't
  1550. X     match that following line 1.
  1551. X     (We used to alter the character after line 1,
  1552. X     but that caused trouble if line 2 directly follows line 1.)  */
  1553. X  savechar = s2->text[s2->length];
  1554. X  s2->text[s2->length] = s1->text[s1->length] + 1;
  1555. X
  1556. X  /* Now find the first mismatch; this won't go past the
  1557. X     character we just changed.  */
  1558. X  while (*t1++ == *t2++);
  1559. X
  1560. X  /* Undo the alteration.  */
  1561. X  s2->text[s2->length] = savechar;
  1562. X
  1563. X  /* If the comparison stopped at the alteration,
  1564. X     the two lines are identical.  */
  1565. X  if (t2 == s2->text + s2->length + 1)
  1566. X    return 0;
  1567. X
  1568. X  /* Not exactly identical, but perhaps they match anyway
  1569. X     when case or whitespace is ignored.  */
  1570. X
  1571. X  if (ignore_case_flag || ignore_space_change_flag || ignore_all_space_flag)
  1572. X    {
  1573. X      t1 = s1->text;
  1574. X      t2 = s2->text;
  1575. X
  1576. X      while (1)
  1577. X    {
  1578. X      register char c1 = *t1++;
  1579. X      register char c2 = *t2++;
  1580. X
  1581. X      /* Ignore horizontal whitespace if -b or -w is specified.  */
  1582. X
  1583. X      if (ignore_all_space_flag)
  1584. X        {
  1585. X          /* For -w, just skip past any spaces or tabs.  */
  1586. X          while (c1 == ' ' || c1 == '\t') c1 = *t1++;
  1587. X          while (c2 == ' ' || c2 == '\t') c2 = *t2++;
  1588. X        }
  1589. X      else if (ignore_space_change_flag)
  1590. X        {
  1591. X          /* For -b, advance past any sequence of whitespace in line 1
  1592. X         and consider it just one Space, or nothing at all
  1593. X         if it is at the end of the line.  */
  1594. X          if (c1 == ' ' || c1 == '\t')
  1595. X        {
  1596. X          while (1)
  1597. X            {
  1598. X              c1 = *t1++;
  1599. X              if (c1 == end_char)
  1600. X            break;
  1601. X              if (c1 != ' ' && c1 != '\t')
  1602. X            {
  1603. X              --t1;
  1604. X              c1 = ' ';
  1605. X              break;
  1606. X            }
  1607. X            }
  1608. X        }
  1609. X
  1610. X          /* Likewise for line 2.  */
  1611. X          if (c2 == ' ' || c2 == '\t')
  1612. X        {
  1613. X          while (1)
  1614. X            {
  1615. X              c2 = *t2++;
  1616. X              if (c2 == end_char)
  1617. X            break;
  1618. X              if (c2 != ' ' && c2 != '\t')
  1619. X            {
  1620. X              --t2;
  1621. X              c2 = ' ';
  1622. X              break;
  1623. X            }
  1624. X            }
  1625. X        }
  1626. X        }
  1627. X
  1628. X      /* Upcase all letters if -i is specified.  */
  1629. X
  1630. X      if (ignore_case_flag)
  1631. X        {
  1632. X          if (islower (c1))
  1633. X        c1 = toupper (c1);
  1634. X          if (islower (c2))
  1635. X        c2 = toupper (c2);
  1636. X        }
  1637. X
  1638. X      if (c1 != c2)
  1639. X        break;
  1640. X      if (c1 == end_char)
  1641. X        return 0;
  1642. X    }
  1643. X    }
  1644. X
  1645. X  return (1);
  1646. X}
  1647. X
  1648. X/* Find the consecutive changes at the start of the script START.
  1649. X   Return the last link before the first gap.  */
  1650. X
  1651. Xstruct change *
  1652. Xfind_change (start)
  1653. X     struct change *start;
  1654. X{
  1655. X  return start;
  1656. X}
  1657. X
  1658. Xstruct change *
  1659. Xfind_reverse_change (start)
  1660. X     struct change *start;
  1661. X{
  1662. X  return start;
  1663. X}
  1664. X
  1665. X/* Divide SCRIPT into pieces by calling HUNKFUN and
  1666. X   print each piece with PRINTFUN.
  1667. X   Both functions take one arg, an edit script.
  1668. X
  1669. X   HUNKFUN is called with the tail of the script
  1670. X   and returns the last link that belongs together with the start
  1671. X   of the tail.
  1672. X
  1673. X   PRINTFUN takes a subscript which belongs together (with a null
  1674. X   link at the end) and prints it.  */
  1675. X
  1676. Xvoid
  1677. Xprint_script (script, hunkfun, printfun)
  1678. X     struct change *script;
  1679. X     struct change * (*hunkfun) ();
  1680. X     void (*printfun) ();
  1681. X{
  1682. X  struct change *next = script;
  1683. X
  1684. X  while (next)
  1685. X    {
  1686. X      struct change *this, *end;
  1687. X
  1688. X      /* Find a set of changes that belong together.  */
  1689. X      this = next;
  1690. X      end = (*hunkfun) (next);
  1691. X
  1692. X      /* Disconnect them from the rest of the changes,
  1693. X     making them a hunk, and remember the rest for next iteration.  */
  1694. X      next = end->link;
  1695. X      end->link = NULL;
  1696. X#ifdef DEBUG
  1697. X      debug_script (this);
  1698. X#endif
  1699. X
  1700. X      /* Print this hunk.  */
  1701. X      (*printfun) (this);
  1702. X
  1703. X      /* Reconnect the script so it will all be freed properly.  */
  1704. X      end->link = next;
  1705. X    }
  1706. X}
  1707. X
  1708. X/* Print the text of a single line LINE,
  1709. X   flagging it with the characters in LINE_FLAG (which say whether
  1710. X   the line is inserted, deleted, changed, etc.).  */
  1711. X
  1712. Xvoid
  1713. Xprint_1_line (line_flag, line)
  1714. X     char *line_flag;
  1715. X     struct line_def *line;
  1716. X{
  1717. X  int length = line->length; /* must be nonzero */
  1718. X  const char *text = line->text; /* Help the compiler.  */
  1719. X  FILE *out = outfile; /* Help the compiler some more.  */
  1720. X
  1721. X  /* If -T was specified, use a Tab between the line-flag and the text.
  1722. X     Otherwise use a Space (as Unix diff does).
  1723. X     Print neither space nor tab if line-flags are empty.  */
  1724. X
  1725. X  if (line_flag != NULL && line_flag[0] != 0)
  1726. X    fprintf (out, tab_align_flag ? "%s\t" : "%s ", line_flag);
  1727. X
  1728. X  /* Now output the contents of the line.
  1729. X     If -t was specified, expand tabs to spaces.
  1730. X     Otherwise output verbatim.  */
  1731. X
  1732. X  if (tab_expand_flag)
  1733. X    {
  1734. X      register int column = 0;
  1735. X      register int i;
  1736. X      for (i = 0; i < line->length; i++)
  1737. X    {
  1738. X      register char c = line->text[i];
  1739. X      switch (c)
  1740. X        {
  1741. X        case '\t':
  1742. X          column++;
  1743. X          while (column & 7)
  1744. X        {
  1745. X          putc (' ', out);
  1746. X          column++;
  1747. X        }
  1748. X          c = ' ';
  1749. X          break;
  1750. X        case '\b':
  1751. X          column--;
  1752. X          break;
  1753. X        default:
  1754. X          column++;
  1755. X          break;
  1756. X        }
  1757. X      putc (c, out);
  1758. X    }
  1759. X    }
  1760. X  else
  1761. X    fwrite (text, sizeof (char), length, out);
  1762. X  if ((line_flag == NULL || line_flag[0] != 0) && text[length - 1] != '\n'
  1763. X      && line_end_char == '\n')
  1764. X    fprintf (out, "\n\\ No newline at end of file\n");
  1765. X}
  1766. X
  1767. Xchange_letter (inserts, deletes)
  1768. X     int inserts, deletes;
  1769. X{
  1770. X  if (!inserts)
  1771. X    return 'd';
  1772. X  else if (!deletes)
  1773. X    return 'a';
  1774. X  else
  1775. X    return 'c';
  1776. X}
  1777. X
  1778. X/* Translate an internal line number (an index into diff's table of lines)
  1779. X   into an actual line number in the input file.
  1780. X   The internal line number is LNUM.  FILE points to the data on the file.
  1781. X
  1782. X   Internal line numbers count from 0 within the current chunk.
  1783. X   Actual line numbers count from 1 within the entire file;
  1784. X   in addition, they include lines ignored for comparison purposes.
  1785. X
  1786. X   The `ltran' feature is no longer in use.  */
  1787. X
  1788. Xint
  1789. Xtranslate_line_number (file, lnum)
  1790. X     struct file_data *file;
  1791. X     int lnum;
  1792. X{
  1793. X  return lnum + 1;
  1794. X}
  1795. X
  1796. Xvoid
  1797. Xtranslate_range (file, a, b, aptr, bptr)
  1798. X     struct file_data *file;
  1799. X     int a, b;
  1800. X     int *aptr, *bptr;
  1801. X{
  1802. X  *aptr = translate_line_number (file, a - 1) + 1;
  1803. X  *bptr = translate_line_number (file, b + 1) - 1;
  1804. X}
  1805. X
  1806. X/* Print a pair of line numbers with SEPCHAR, translated for file FILE.
  1807. X   If the two numbers are identical, print just one number.
  1808. X
  1809. X   Args A and B are internal line numbers.
  1810. X   We print the translated (real) line numbers.  */
  1811. X
  1812. Xvoid
  1813. Xprint_number_range (sepchar, file, a, b)
  1814. X     char sepchar;
  1815. X     struct file_data *file;
  1816. X     int a, b;
  1817. X{
  1818. X  int trans_a, trans_b;
  1819. X  translate_range (file, a, b, &trans_a, &trans_b);
  1820. X
  1821. X  /* Note: we can have B < A in the case of a range of no lines.
  1822. X     In this case, we should print the line number before the range,
  1823. X     which is B.  */
  1824. X  if (trans_b > trans_a)
  1825. X    fprintf (outfile, "%d%c%d", trans_a, sepchar, trans_b);
  1826. X  else
  1827. X    fprintf (outfile, "%d", trans_b);
  1828. X}
  1829. X
  1830. X/* Look at a hunk of edit script and report the range of lines in each file
  1831. X   that it applies to.  HUNK is the start of the hunk, which is a chain
  1832. X   of `struct change'.  The first and last line numbers of file 0 are stored in
  1833. X   *FIRST0 and *LAST0, and likewise for file 1 in *FIRST1 and *LAST1. 
  1834. X   Note that these are internal line numbers that count from 0.
  1835. X
  1836. X   If no lines from file 0 are deleted, then FIRST0 is LAST0+1.
  1837. X
  1838. X   Also set *DELETES nonzero if any lines of file 0 are deleted
  1839. X   and set *INSERTS nonzero if any lines of file 1 are inserted.
  1840. X   If only ignorable lines are inserted or deleted, both are
  1841. X   set to 0.  */
  1842. X
  1843. Xvoid
  1844. Xanalyze_hunk (hunk, first0, last0, first1, last1, deletes, inserts)
  1845. X     struct change *hunk;
  1846. X     int *first0, *last0, *first1, *last1;
  1847. X     int *deletes, *inserts;
  1848. X{
  1849. X  int f0, l0, f1, l1, show_from, show_to;
  1850. X  int i;
  1851. X  int nontrivial = !(ignore_blank_lines_flag || ignore_regexp);
  1852. X  struct change *next;
  1853. X
  1854. X  show_from = show_to = 0;
  1855. X
  1856. X  f0 = hunk->line0;
  1857. X  f1 = hunk->line1;
  1858. X
  1859. X  for (next = hunk; next; next = next->link)
  1860. X    {
  1861. X      l0 = next->line0 + next->deleted - 1;
  1862. X      l1 = next->line1 + next->inserted - 1;
  1863. X      show_from += next->deleted;
  1864. X      show_to += next->inserted;
  1865. X
  1866. X      for (i = next->line0; i <= l0 && ! nontrivial; i++)
  1867. X    if ((!ignore_blank_lines_flag || files[0].linbuf[i].length > 1)
  1868. X        && (!ignore_regexp
  1869. X        || 0 > re_search (&ignore_regexp_compiled,
  1870. X                  files[0].linbuf[i].text,
  1871. X                  files[0].linbuf[i].length, 0,
  1872. X                  files[0].linbuf[i].length, 0)))
  1873. X      nontrivial = 1;
  1874. X
  1875. X      for (i = next->line1; i <= l1 && ! nontrivial; i++)
  1876. X    if ((!ignore_blank_lines_flag || files[1].linbuf[i].length > 1)
  1877. X        && (!ignore_regexp
  1878. X        || 0 > re_search (&ignore_regexp_compiled,
  1879. X                  files[1].linbuf[i].text,
  1880. X                  files[1].linbuf[i].length, 0,
  1881. X                  files[1].linbuf[i].length, 0)))
  1882. X      nontrivial = 1;
  1883. X    }
  1884. X
  1885. X  *first0 = f0;
  1886. X  *last0 = l0;
  1887. X  *first1 = f1;
  1888. X  *last1 = l1;
  1889. X
  1890. X  /* If all inserted or deleted lines are ignorable,
  1891. X     tell the caller to ignore this hunk.  */
  1892. X
  1893. X  if (!nontrivial)
  1894. X    show_from = show_to = 0;
  1895. X
  1896. X  *deletes = show_from;
  1897. X  *inserts = show_to;
  1898. X}
  1899. X
  1900. X/* malloc a block of memory, with fatal error message if we can't do it. */
  1901. X
  1902. XVOID *
  1903. Xxmalloc (size)
  1904. X     unsigned size;
  1905. X{
  1906. X  register VOID *value;
  1907. X
  1908. X  if (size == 0)
  1909. X    size = 1;
  1910. X
  1911. X  value = (VOID *) malloc (size);
  1912. X
  1913. X  if (!value)
  1914. X    fatal ("virtual memory exhausted");
  1915. X  return value;
  1916. X}
  1917. X
  1918. X/* realloc a block of memory, with fatal error message if we can't do it. */
  1919. X
  1920. XVOID *
  1921. Xxrealloc (old, size)
  1922. X     VOID *old;
  1923. X     unsigned int size;
  1924. X{
  1925. X  register VOID *value;
  1926. X
  1927. X  if (size == 0)
  1928. X    size = 1;
  1929. X
  1930. X  value = (VOID *) realloc (old, size);
  1931. X
  1932. X  if (!value)
  1933. X    fatal ("virtual memory exhausted");
  1934. X  return value;
  1935. X}
  1936. X
  1937. X/* Concatenate three strings, returning a newly malloc'd string.  */
  1938. X
  1939. Xchar *
  1940. Xconcat (s1, s2, s3)
  1941. X     char *s1, *s2, *s3;
  1942. X{
  1943. X  int len = strlen (s1) + strlen (s2) + strlen (s3);
  1944. X  char *new = (char *) xmalloc (len + 1);
  1945. X  strcpy (new, s1);
  1946. X  strcat (new, s2);
  1947. X  strcat (new, s3);
  1948. X  return new;
  1949. X}
  1950. X
  1951. Xdebug_script (sp)
  1952. X     struct change *sp;
  1953. X{
  1954. X  fflush (stdout);
  1955. X  for (; sp; sp = sp->link)
  1956. X    fprintf (stderr, "%3d %3d delete %d insert %d\n",
  1957. X         sp->line0, sp->line1, sp->deleted, sp->inserted);
  1958. X  fflush (stderr);
  1959. X}
  1960. END_OF_FILE
  1961. if test 14888 -ne `wc -c <'util.c'`; then
  1962.     echo shar: \"'util.c'\" unpacked with wrong size!
  1963. fi
  1964. # end of 'util.c'
  1965. fi
  1966. echo shar: End of archive 3 \(of 8\).
  1967. cp /dev/null ark3isdone
  1968. MISSING=""
  1969. for I in 1 2 3 4 5 6 7 8 ; do
  1970.     if test ! -f ark${I}isdone ; then
  1971.     MISSING="${MISSING} ${I}"
  1972.     fi
  1973. done
  1974. if test "${MISSING}" = "" ; then
  1975.     echo You have unpacked all 8 archives.
  1976.     rm -f ark[1-9]isdone
  1977. else
  1978.     echo You still need to unpack the following archives:
  1979.     echo "        " ${MISSING}
  1980. fi
  1981. ##  End of shell archive.
  1982. exit 0
  1983.  
  1984. exit 0 # Just in case...
  1985.